package raft

import (
    "sync"
    "time"
    "math/rand"
    "fmt"
)

const (
    Follower = iota
    Candidate
    Leader
)

type LogEntry struct {
    Command string
    Term    int
}

type Raft struct {
    mu              sync.Mutex
    peers           []*PeerClient
    me              int
    state           int
    currentTerm     int
    votedFor        int
    log             []LogEntry
    commitIndex     int
    lastApplied     int
    electionTimeout time.Duration
    heartbeatInterval time.Duration
    voteCh          chan bool
    applyCh         chan LogEntry
}

// 创建一个新的 Raft 节点
func Make(peers []*PeerClient, me int, applyCh chan LogEntry) *Raft {
    rf := &Raft{
        peers:             peers,
        me:                me,
        state:             Follower,
        currentTerm:       0,
        votedFor:          -1,
        log:               []LogEntry{},
        commitIndex:       0,
        lastApplied:       0,
        electionTimeout:   time.Duration(150 + rand.Intn(150)) * time.Millisecond,
        heartbeatInterval: 50 * time.Millisecond,
        voteCh:            make(chan bool),
        applyCh:           applyCh,
    }

    go rf.startElection()
    go rf.startHeartbeat()

    return rf
}

// convertToFollower 将节点状态转换为 Follower
func (rf *Raft) convertToFollower(term int) {
    rf.currentTerm = term
    rf.votedFor = -1
    rf.state = Follower
    fmt.Printf("Node %d converted to Follower with term %d\n", rf.me, term)
}

// startHeartbeat 定期发送心跳（Leader 发送 AppendEntries RPC）
func (rf *Raft) startHeartbeat() {
    for {
        rf.mu.Lock()
        if rf.state == Leader {
            rf.mu.Unlock()
            for i := 0; i < len(rf.peers); i++ {
                if i != rf.me {
                    go func(peer *PeerClient) {
                        args := AppendEntriesArgs{
                            Term:     rf.currentTerm,
                            LeaderID: rf.me,
                            Entries:  []LogEntry{}, // 心跳没有日志条目
                        }
                        var reply AppendEntriesReply
                        rf.sendAppendEntries(peer, &args, &reply)
                    }(rf.peers[i])
                }
            }
        } else {
            rf.mu.Unlock()
        }
        time.Sleep(rf.heartbeatInterval)
    }
}

// startElection 启动选举过程
func (rf *Raft) startElection() {
    for {
        time.Sleep(rf.electionTimeout)
        rf.mu.Lock()
        if rf.state != Leader {
            rf.state = Candidate
            rf.currentTerm++
            rf.votedFor = rf.me
            rf.mu.Unlock()

            var votes int32 = 1
            var done int32
            for i := 0; i < len(rf.peers); i++ {
                if i != rf.me {
                    go func(peer *PeerClient) {
                        rf.mu.Lock()
                        lastLogIndex := len(rf.log) - 1
                        lastLogTerm := 0
                        if lastLogIndex >= 0 {
                            lastLogTerm = rf.log[lastLogIndex].Term
                        }
                        rf.mu.Unlock()

                        args := RequestVoteArgs{
                            Term:        rf.currentTerm,
                            CandidateID: rf.me,
                            LastLogIndex: lastLogIndex,
                            LastLogTerm:  lastLogTerm,
                        }
                        var reply RequestVoteReply
                        if rf.sendRequestVote(peer, &args, &reply) && reply.VoteGranted {
                            votes++
                        }
                        done++
                    }(rf.peers[i])
                }
            }

            rf.mu.Lock()
            if votes > int32(len(rf.peers)/2) {
                rf.state = Leader
                fmt.Printf("Node %d is the new Leader\n", rf.me)
            } else {
                rf.state = Follower
            }
            rf.mu.Unlock()
        } else {
            rf.mu.Unlock()
        }
    }
}
